package timer

import (
	"src/zeus/common"
	"src/zeus/iserver"
	"src/zeus/logger"
	"sync"
)

func newCallbackMap() *callbackMap {
	return &callbackMap{
		callbacks: make(map[int]*funcInfo),
		onlyRead:  nil,
	}
}

type callbackMap struct {
	callbacks map[int]*funcInfo
	onlyRead  map[int]*funcInfo
	mu        sync.Mutex
}

func (t *callbackMap) Find(key int) (*funcInfo, bool) {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.onlyRead != nil {
		if v, ok := t.onlyRead[key]; ok {
			return v, ok
		}
	}
	v, ok := t.callbacks[key]
	return v, ok
}

func (t *callbackMap) Add(key int, val *funcInfo) {
	if val == nil {
		return
	}
	t.mu.Lock()
	defer t.mu.Unlock()

	t.callbacks[key] = val
}

func (t *callbackMap) Remove(key int) {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.onlyRead != nil {
		t.callbacks[key] = nil
	} else {
		delete(t.callbacks, key)
	}
}

func (t *callbackMap) Loop(visitor func(key int, val *funcInfo) (Break bool)) {
	t.mu.Lock()
	if len(t.callbacks) == 0 {
		t.mu.Unlock()
		return
	}
	copyForLoop := t.callbacks
	tempMap := make(map[int]*funcInfo)
	t.callbacks = tempMap
	t.onlyRead = copyForLoop
	t.mu.Unlock()
	defer func() {
		if err := recover(); err != nil {
			logger.Error(err)
			buf := common.StackTrace()
			common.UpPanic(common.NewPanicSrvMD(
				int(iserver.GetSrvInst().GetGroupId()),
				int(iserver.GetSrvInst().GetSrvType()),
				int(iserver.GetSrvInst().GetCurSrvInfo().ServerID),
				"",
				err,
				buf,
			))
		}
		t.mu.Lock()
		defer t.mu.Unlock()
		t.onlyRead = nil
		_mergeCallbackMap(tempMap, &copyForLoop)
		t.callbacks = copyForLoop
	}()
	for k, f := range copyForLoop {
		if visitor(k, f) {
			break
		}
	}
}

func _mergeCallbackMap(from map[int]*funcInfo, to *map[int]*funcInfo) {
	if from == nil || to == nil {
		return
	}

	for k, v := range from {
		if v == nil {
			delete(*to, k)
		} else {
			(*to)[k] = v
		}
	}
}

func (t *callbackMap) MergeTemp(temp *callbackMap) {
	if temp == nil {
		return
	}

	for k, v := range temp.callbacks {
		if v == nil {
			t.Remove(k)
		} else {
			t.Add(k, v)
		}
	}
}
